/********************************************************************************
 * @file    hal_uart.c
 * @brief   串口通讯
 * 
 * @author  nzttj
 * @date    2025-02-13
 * @version 1.0
 * 
 * Copyright (C) 2025 nzttj
 * 
 * 本软件使用 GNU 通用公共许可证 (GPL) 第 3 版授权。
 * 
 * 您可以自由使用、修改、分发本软件，但必须遵守以下条件：
 * 1. 源代码必须开放，且您修改后的代码也必须以 GPL 许可证发布。
 * 2. 发布或分发本软件时，必须附带本许可证，并提供源代码或获取源代码的方式。
 * 
 * 本软件按“原样”提供，不附带任何担保，使用风险由用户自行承担。
 * 
 ********************************************************************************/

#include "hal_uart.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "esp_log.h"

#define MAX_UART_NUM (2)
#define USER_UART_BUF_SIZE (256)

static const char *TAG = "hal_uart";
static QueueHandle_t uart_queue[MAX_UART_NUM];
static uart_rx_cb_t s_uart_rx_cb[MAX_UART_NUM];

static void _uart_event_task(void *param)
{
    uart_event_t event;
    uint8_t *dtmp = (uint8_t *)malloc(USER_UART_BUF_SIZE);
    uart_port_t uart_num = (uart_port_t)param;

    for (;;)
    {
        if (xQueueReceive(uart_queue[uart_num], (void *)&event, portMAX_DELAY))
        {
            switch (event.type)
            {
            case UART_DATA:
                uart_read_bytes(uart_num, dtmp, event.size, portMAX_DELAY);
                if (s_uart_rx_cb[uart_num])
                {
                    s_uart_rx_cb[uart_num](dtmp, event.size);
                }
                break;
            case UART_FIFO_OVF:
                ESP_LOGI(TAG, "hw fifo overflow");
                uart_flush_input(uart_num);
                xQueueReset(uart_queue[uart_num]);
                break;
            case UART_BUFFER_FULL:
                ESP_LOGI(TAG, "ring buffer full");
                uart_flush_input(uart_num);
                xQueueReset(uart_queue[uart_num]);
                break;
            case UART_PARITY_ERR:
                ESP_LOGI(TAG, "uart parity error");
                break;
            case UART_FRAME_ERR:
                ESP_LOGI(TAG, "uart frame error");
                break;
            default:
                ESP_LOGI(TAG, "uart event type: %d", event.type);
                break;
            }
        }
    }
}

int hal_uart_init(int uart_num, int baud_rate, uart_rx_cb_t rx_cb)
{
    s_uart_rx_cb[uart_num] = rx_cb;

    uart_config_t uart_config = {
        .baud_rate = baud_rate,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
    };

    // 配置串口参数
    uart_param_config(uart_num, &uart_config);
    // 配置串口队列
    uart_driver_install(uart_num, USER_UART_BUF_SIZE * 2, USER_UART_BUF_SIZE * 2, 5, &uart_queue[uart_num], 0);
    // 创建串口事件任务
    xTaskCreate(_uart_event_task, "uart_event_task", 2048, (void *)uart_num, 12, NULL);

    return 0;
}

int hal_uart_write_bytes(int uart_num, const void *src, size_t size)
{
    return uart_write_bytes((uart_port_t)uart_num, src, size);
}
